﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SnelsteRoute
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, System.ComponentModel.INotifyPropertyChanged
    {
        private Configuration _selectedConfiguration = null;
        public Configuration SelectedConfiguration { get { return _selectedConfiguration; } private set { _selectedConfiguration = value; NotifyPropertyChanged("SelectedConfiguration"); } }

        private List<Route> _foundRoutes = null;
        public List<Route> FoundRoutes { get { return _foundRoutes; } private set { _foundRoutes = value; NotifyPropertyChanged("FoundRoutes"); } }

        private readonly BackgroundWorker _searchWorker = new BackgroundWorker();
        private readonly Window _progressWindow = new Progress();

        private long _tickCountStart = 0;

        public MainWindow()
        {
            InitializeComponent();

            _searchWorker.WorkerSupportsCancellation = true;
            _searchWorker.DoWork += new DoWorkEventHandler(_searchWorker_DoWork);
            _searchWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_searchWorker_RunWorkerCompleted);

            var maxNrOfSquares = ConfigHelper.GetInt32(ConfigHelper.ConfigMaxNrOfSquares, 7);
            for (var i = 1; i <= maxNrOfSquares; i++)
            {
                desiredHops.Items.Add(i);
            }

            if (maxNrOfSquares >= 3)
                desiredHops.SelectedItem = 3;

        }

        private void MainWindowRef_Activated(object sender, EventArgs e)
        {
            _progressWindow.Owner = this;
            _progressWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
        }

        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
            }
        }

        private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            SelectedConfiguration = (sender as ComboBox).SelectedItem as Configuration;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            FoundRoutes = null;

            if (!IsValid())
                return;

            var maxHops = ((Int32) desiredHops.SelectedItem + 2);
            var request = new SearchRequest()
            {
                From = FromAspect.SelectedItem as Aspect,
                To = ToAspect.SelectedItem as Aspect,
                MaxHops = maxHops
            };

            Models.GetInstance().LocatedRoutes = 0;
            Models.GetInstance().FinishedRoutes = 0;

            _progressWindow.Show();

            _tickCountStart = Environment.TickCount;
            _searchWorker.RunWorkerAsync(request);
        }

        private bool IsValid()
        {
            errorMessages.Content = String.Empty;
            if (SelectedConfiguration == null)
            {
                errorMessages.Content = "Select a configuration";
                return false;
            }

            if (FromAspect.SelectedItem == null)
            {
                errorMessages.Content = "Select a from aspect";
                return false;
            }
            if (ToAspect.SelectedItem == null)
            {
                errorMessages.Content = "Select a to aspect";
                return false;
            }

            if (desiredHops.SelectedItem == null)
            {
                errorMessages.Content = "Select nr of hops";
                return false;
            }
            return true;
        }

        void _searchWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            if (!(e.Argument is SearchRequest))
            {
                throw new Exception("Invalid searchRequest");
            }

            var req = e.Argument as SearchRequest;
            e.Result = RouteFinder.FindRoutes(req);
        }

        void _searchWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (!(e.Result is List<Route>))
                MessageBox.Show(this, "Invalid object returned from search", "Error", MessageBoxButton.OK,
                    MessageBoxImage.Error);

            var maxHops = ((Int32)desiredHops.SelectedItem + 2); 
            var routes = e.Result as List<Route>;
            var displayLimit = ConfigHelper.GetInt32(ConfigHelper.ConfigDisplayLimit, 10);
            // order by cost, filter out the routes that are too short
            FoundRoutes = routes.OrderBy(r => r.Cost).Where(r => r.NrOfHops == maxHops).Take(displayLimit).ToList();

            _progressWindow.Hide();

            var models = Models.GetInstance();
            var timeSpent = Environment.TickCount - _tickCountStart;

            if (models.FinishedRoutes == 0)
            {
                statistics.Content = "No valid route found, try adding a square";
            }
            else
            {
                statistics.Content =
                     String.Format("{0} routes queried, {1} found, showing max {2} routes(config), this took {3}ms",
                     models.LocatedRoutes,
                     models.FinishedRoutes,
                     displayLimit,
                     timeSpent); 
            }
        }

        private void MainWindowRef_Closed(object sender, EventArgs e)
        {
            Application.Current.Shutdown();
        }

        private void swapBtn_Click(object sender, RoutedEventArgs e)
        {
            var temp = FromAspect.SelectedIndex;
            FromAspect.SelectedIndex = ToAspect.SelectedIndex;
            ToAspect.SelectedIndex = temp;
        }

    }
}
